﻿using Sayook.Framework.DbCore.SqlModel;
using System;
using System.Linq;
using System.Linq.Expressions;

namespace Sayook.Framework.DbCore.CreateSqlString
{
    /// <summary>
    /// 生产Sql语句基础类
    /// </summary>
    public class CreateSqlBase
    {
        protected static readonly object obj = new object();

        /// <summary>
        /// 解析 表名
        /// </summary>
        /// <typeparam name="T">数据库模型类型</typeparam>
        /// <returns>表名</returns>
        protected string ParseTableName<T>() where T : DbModelBase
        {
            var type = typeof(T);
            var attribute = type.GetCustomAttributes(typeof(DbTableAttribute), false).FirstOrDefault();
            var tableName = ((DbTableAttribute)attribute)?.TableName;
            return tableName;
        }

        /// <summary>
        /// 生成 SELECT 字句
        /// </summary>
        /// <typeparam name="T">数据库模型类</typeparam>
        /// <returns>"SELECT * FROM tableName"</returns>
        public string CreateSelect<T>() where T : DbModelBase
        {
            var selectFileds = SqlKeyWord.FiledAll;
            return string.Format(SqlKeyWord.Select, selectFileds, ParseTableName<T>());
        }

        /// <summary>
        /// 生成 SELECT 字句
        /// </summary>
        /// <typeparam name="T">数据库模型类</typeparam>
        /// <param name="expression">查询字段表达式 eg:x => new { x.Id, x.Name, ...}</param>
        /// <returns>"SELECT field1,field2... FROM tableName"</returns>
        public string CreateSelect<T>(Expression<Func<T, object>> expression) where T : DbModelBase
        {
            var selectFileds = expression.ParseSelectExpression();
            return string.Format(SqlKeyWord.Select, selectFileds, ParseTableName<T>());
        }

        /// <summary>
        ///  生成 SELECT DISTINCT 字句
        /// </summary>
        /// <typeparam name="T">数据库模型类型</typeparam>
        /// <typeparam name="TElement">查询字段的类型</typeparam>
        /// <param name="expression">查询字段表达式 eg:x => x.Name</param>
        /// <returns>"SELECT DISTINCT 字段名 FROM 表名称"</returns>
        public string CreateSelectDistinct<T, TElement>(Expression<Func<T, TElement>> expression) where T : DbModelBase
        {
            var selectFiled = expression.ParseSelectDistinctExpression();
            return string.Format(SqlKeyWord.SelectDistinct, selectFiled, ParseTableName<T>());
        }

        /// <summary>
        /// 生成 WHERE 字句
        /// </summary>
        /// <typeparam name="T">数据库模型类</typeparam>
        /// <param name="expression">条件字段表达式 eg:x => SqlWhere.Where(x.Id, SqlOperator.Equal)</param>
        /// <returns>"WHERE field = @field"</returns>
        public string CreateWhere<T>(Expression<Func<T, SqlWhere>> expression)
        {
            return $"{SqlKeyWord.Where}{expression.ParseWhereExpression()}";
        }

        /// <summary>
        /// 生成 AND 字句
        /// </summary>
        /// <typeparam name="T">数据库模型类</typeparam>
        /// <param name="expression">条件字段表达式 eg:x => SqlWhere.Where(x.Name, SqlOperator.Unqual)</param>
        /// <returns>"AND field <> @field"</returns>
        public string CreateAnd<T>(Expression<Func<T, SqlWhere>> expression)
        {
            return $"{SqlKeyWord.And}{expression.ParseWhereExpression()}";
        }

        /// <summary>
        /// 生成 OR 字句
        /// </summary>
        /// <typeparam name="T">数据库模型类</typeparam>
        /// <param name="expression">条件字段表达式 eg:x => SqlWhere.Where(x.Id, SqlOperator.Less)</param>
        /// <returns>"OR field < @field"</returns>
        public string CreateOr<T>(Expression<Func<T, SqlWhere>> expression)
        {
            return $"{SqlKeyWord.Or}{expression.ParseWhereExpression()}";
        }

        /// <summary>
        /// 生成 ORDER BY 字句
        /// </summary>
        /// <typeparam name="T">数据库模型类型</typeparam>
        /// <typeparam name="TElement">排序字段类型</typeparam>
        /// <param name="expression">ORDER BY表达式 eg:x => x.Id</param>
        /// <returns>"field ASC"</returns>
        public string CreateOrderBy<T, TElement>(Expression<Func<T, TElement>> expression)
        {
            return $"{expression.ParseOrderbyExpression()}{SqlKeyWord.OrdeybyAsc}";
        }

        /// <summary>
        /// 生成 ORDER BY DESC 字句
        /// </summary>
        /// <typeparam name="T">数据库模型类型</typeparam>
        /// <typeparam name="TElement">排序字段类型</typeparam>
        /// <param name="expression">ORDER BY表达式 eg:x => x.Id</param>
        /// <returns>"field DESC"</returns>
        public string CreateOrderByDesc<T, TElement>(Expression<Func<T, TElement>> expression)
        {
            return $"{expression.ParseOrderbyExpression()}{SqlKeyWord.OrdeybyDesc}";
        }

        /// <summary>
        ///  生成 INSERT 语句
        /// </summary>
        /// <typeparam name="T">数据库模型类型</typeparam>
        /// <typeparam name="TElement">更新字段的类型</typeparam>
        /// <param name="expression">新增记录的表达式:x => new { x.Id, x.Name }</param>
        /// <returns></returns>
        public string CreateInsert<T, TElement>(Expression<Func<T, TElement>> expression) where T : DbModelBase
        {
            var (filds, values) = expression.ParseInsertExpression();
            return string.Format(SqlKeyWord.Insert, ParseTableName<T>(), filds, values);
        }

        /// <summary>
        /// 生成 UPDATE 字句
        /// </summary>
        /// <typeparam name="T">数据库模型类型</typeparam>
        /// <typeparam name="TElement">更新字段的类型</typeparam>
        /// <param name="expression">更新字段的表达式 eg:x => new { x.Name, x.Remark }</param>
        /// <returns> "UPDATE tableName SET Name = @name,Remark = @Remark"</returns>
        public string CreateUpdate<T, TElement>(Expression<Func<T, TElement>> expression) where T : DbModelBase
        {
            return string.Format(SqlKeyWord.Update, ParseTableName<T>(), expression.ParseUpdateExpression());
        }

        /// <summary>
        /// 生成 DELETE 语句
        /// </summary>
        /// <typeparam name="T">数据库模型类型</typeparam>
        /// <returns></returns>
        public string CreateDelete<T>() where T : DbModelBase
        {
            return string.Format(SqlKeyWord.Delete, ParseTableName<T>());
        }
    }
}